package com.ccc.boot.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ccc.boot.base.BaseServiceImpl;
import com.ccc.boot.constant.CommonConstant;
import com.ccc.boot.constant.DictConstant;
import com.ccc.boot.exception.BusinessException;
import com.ccc.boot.pojo.BaseTree;
import com.ccc.boot.pojo.MenuTree;
import com.ccc.boot.pojo.Meta;
import com.ccc.boot.response.ResponseCode;
import com.ccc.boot.system.entity.SysApi;
import com.ccc.boot.system.entity.SysMenu;
import com.ccc.boot.system.mapper.SysMenuMapper;
import com.ccc.boot.system.pojo.AuthMenuTree;
import com.ccc.boot.system.pojo.AuthMenuVO;
import com.ccc.boot.system.pojo.SysMenuTree;
import com.ccc.boot.system.service.RelRoleResourceService;
import com.ccc.boot.system.service.SysApiService;
import com.ccc.boot.system.service.SysMenuService;
import com.ccc.boot.util.TreeUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 菜单——服务层
 *
 * @author superC
 * @version 0.1.0
 * @date 2022/3/25
 */

@Service
public class SysMenuServiceImpl extends BaseServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysApiService sysApiService;

    @Autowired
    private RelRoleResourceService relRoleResourceService;

    @Override
    public boolean insert(SysMenu entity) {
        if (TreeUtils.ROOT_NODE.equals(entity.getPid())) {
            entity.setType(DictConstant.MENU_TYPE_TOP_LEVEL);
        } else {
            entity.setType(DictConstant.MENU_TYPE_SON);
        }
        return super.insert(entity);
    }

    @Override
    public List<SysMenuTree> getAllMenuTree() {
        List<SysMenuTree> list = baseMapper.getAll();
        if (list.size() > 0) {
            return bulidSysMenuTree(list, TreeUtils.ROOT_NODE.longValue());
        }
        return null;
    }

    /**
     * 获取所有菜单（有效）树形结构
     *
     * @return {@link List< MenuTree>}
     * @date 2022/4/19 17:43
     * @author superC
     */
    @Override
    public List<MenuTree> getEnabledMenuTree() {
        // 获取所有有效的菜单集
        List<SysMenu> list = getEnabledMenus(null);
        if (list.size() > 0) {
            // 转换Bean
            List<MenuTree> treeList = this.transProperties(list);
            return TreeUtils.bulid(treeList, TreeUtils.ROOT_NODE.longValue());
        }
        return new ArrayList<>();
    }

    /**
     * 构建菜单表的树（用于菜单管理）
     *
     * @param treeNodes 传入的树节点列表
     * @param root      所需树的根节点
     * @return {@link List< SysMenuTree>}
     * @date 2022/3/31 16:15
     * @author superC
     */
    private List<SysMenuTree> bulidSysMenuTree(List<SysMenuTree> treeNodes, Long root) {
        List<SysMenuTree> trees = new ArrayList<>();
        for (SysMenuTree treeNode : treeNodes) {
            // 根节点
            if (root.equals(treeNode.getPid())) {
                trees.add(treeNode);
            }
            for (SysMenuTree it : treeNodes) {
                if (it.getPid().equals(treeNode.getId())) {
                    treeNode.add(it);
                }
            }
        }
        return trees;
    }

    @Override
    public List<MenuTree> getMenuTree(String rolesStr) {
        // 根据角色集,获取授权的菜单数据
        List<SysMenu> menuList = getMenusByRoles(rolesStr);

        // 据角色集,获取授权的按钮接口资源数据
        List<SysApi> apiList = sysApiService.getApisByRoles(rolesStr);
        // 根据菜单id,分组按钮接口资源
        Map<Long, List<SysApi>> apiListMap = null;
        if (apiList != null && apiList.size() > 0) {
            apiListMap = apiList.stream().collect(Collectors.groupingBy(SysApi::getMenuId));
        }

        // 获取tree
        if (menuList != null && menuList.size() > 0) {
            return generateTree(menuList, apiListMap);
        }
        return null;
    }

    public List<SysMenu> getMenusByRoles(String rolesStr) {
        String[] roleArr = rolesStr.split(CommonConstant.SEPARATOR_COMMA);
//        Set<String> roles = Arrays.stream(roleArr).collect(Collectors.toSet());
        return baseMapper.getMenusByRoles(DictConstant.STATUS_ENABLE, DictConstant.RESOURCE_TYPE_MENU, roleArr);
    }

    /**
     * 获取菜单tree
     */
    private List<MenuTree> generateTree(List<SysMenu> list, Map<Long, List<SysApi>> apiListMap) {
        // 转换Bean
        List<MenuTree> tree = this.transProperties(list, apiListMap);

        // 整合tree
        return TreeUtils.bulid(tree, TreeUtils.ROOT_NODE.longValue());
    }

    /**
     * 转换属性
     *
     * @param list 菜单列表
     * @return {@link List< MenuTree>}
     * @date 2022/4/2 10:21
     * @author superC
     */
    private List<MenuTree> transProperties(List<SysMenu> list) {
        List<MenuTree> tree = new ArrayList<>();
        for (SysMenu baseMenu : list) {
            MenuTree menuTree = new MenuTree();
            menuTree.setId(baseMenu.getId());
            menuTree.setPid(baseMenu.getPid());
            menuTree.setName(baseMenu.getName());
            tree.add(menuTree);
        }
        return tree;
    }

    /**
     * 转换属性
     *
     * @param list       菜单列表
     * @param apiListMap 按钮接口资源集合
     * @return {@link List< MenuTree>}
     * @date 2022/4/2 10:21
     * @author superC
     */
    private List<MenuTree> transProperties(List<SysMenu> list, Map<Long, List<SysApi>> apiListMap) {
        List<MenuTree> tree = new ArrayList<>();
        for (SysMenu baseMenu : list) {
            MenuTree menuTree = new MenuTree();
            BeanUtils.copyProperties(baseMenu, menuTree);
            menuTree.setHidden(yesOrNo(baseMenu.getHidden()));
            Meta meta = new Meta();
            meta.setTitle(baseMenu.getTitle());
            meta.setIcon(baseMenu.getIcon());
            // 按钮接口资源
            if (apiListMap != null) {
                apiListMap.forEach((menuId, apiList) -> {
                    if (menuTree.getId().equals(menuId)) {
                        List<String> apis = apiList.stream().map(SysApi::getApiCode).collect(Collectors.toList());
                        // 添加按钮接口资源编码,至菜单的meta中的apis
                        meta.setApis(apis);
                    }
                });
            }
            menuTree.setMeta(meta);
            tree.add(menuTree);
        }
        return tree;
    }

    private boolean yesOrNo(Integer num) {
        if (num == null) {
            return false;
        }
        if (DictConstant.YES.equals(num)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取当前角色已授权的菜单集
     *
     * @param roleId
     * @return {@link List< AuthMenuTree>}
     * @date 2022/4/8 14:09
     * @author superC
     */
    @Override
    public AuthMenuVO getAuthMenuTree(Long roleId) {
        AuthMenuVO result = new AuthMenuVO();
        // 获取所有菜单（有效）树形结构
        List<MenuTree> treeList = getEnabledMenuTree();
        result.setMenuTree(treeList);

        // 根据角色ID，获取菜单ID集
        List<Long> authMenuIds = relRoleResourceService.getMenuIds(roleId);
        result.setCheckMenuIds(authMenuIds);

        return result;
    }

    /**
     * 获取有效菜单
     *
     * @param wrapper
     * @return {@link List< SysMenu>}
     * @date 2022/3/31 16:06
     * @author superC
     */
    private List<SysMenu> getEnabledMenus(QueryWrapper<SysMenu> wrapper) {
        if (wrapper == null) {
            wrapper = new QueryWrapper<>();
        }
        wrapper.lambda().eq(SysMenu::getStatus, DictConstant.USER_STATUS_OK);
        wrapper.orderByAsc("order_num");
        return baseMapper.selectList(wrapper);
    }

    /**
     * 生成已授权的菜单集
     *
     * @param effectList  所有有效的菜单集
     * @param authMenuIds 授权的菜单ID集
     * @return {@link List< AuthMenuTree>}
     * @date 2022/4/8 14:09
     * @author superC
     */
    private List<AuthMenuTree> generateAuthMenuTree(List<SysMenu> effectList, List<Long> authMenuIds) {
        // 转换Bean
        List<AuthMenuTree> tree = this.transProperties2(effectList, authMenuIds);

        // 整合tree
        return TreeUtils.bulid(tree, TreeUtils.ROOT_NODE.longValue());
    }

    private List<AuthMenuTree> transProperties2(List<SysMenu> effectList, List<Long> authMenuIds) {
        List<AuthMenuTree> tree = new ArrayList<>();
        effectList.forEach(sysMenu -> {
            AuthMenuTree authMenuTree = new AuthMenuTree();
            authMenuTree.setId(sysMenu.getId());
            authMenuTree.setPid(sysMenu.getPid());
            authMenuTree.setName(sysMenu.getName());

            AtomicBoolean isAuthorized = new AtomicBoolean(false);
            if (authMenuIds != null && authMenuIds.size() > 0) {
                authMenuIds.forEach(id -> {
                    if (sysMenu.getId().equals(id)) {
                        isAuthorized.set(true);
                        return;
                    }
                });
            }
            authMenuTree.setAuthorized(isAuthorized.get());
            tree.add(authMenuTree);
        });
        return tree;
    }

    @Override
    public boolean deleteNodes(MenuTree menuTree) {
        this.deleteMenuTree(menuTree);
        return true;
    }

    /**
     * 递归删除节点数据
     */
    private void deleteMenuTree(BaseTree menuTree) {
        // 删除菜单
        boolean delete = this.delete(menuTree.getId());
        if (delete) {
            List<BaseTree> children = menuTree.getChildren();
            if (children != null && children.isEmpty()) {
                for (BaseTree child : children) {
                    // 递归调用
                    this.deleteMenuTree(child);
                }
            }
        }
    }

    @Override
    public boolean delete(Long id) {
        try {
            if (checkId(id)) {
                // 删除角色与菜单中间表
                relRoleResourceService.delete(DictConstant.RESOURCE_TYPE_MENU, id);

                // 获取当前菜单所属按钮接口资源
                List<SysApi> apiList = sysApiService.getAllApis(id);
                if (!apiList.isEmpty()) {
                    List<Long> apiIds = apiList.stream().map(SysApi::getId).collect(Collectors.toList());
                    // 删除当前菜单所属按钮接口资源
                    relRoleResourceService.deleteApis(apiIds);

                    // 删除按钮接口资源
                    sysApiService.removeByIds(apiList);
                }

                // 删除菜单
                return super.removeById(id);
            } else {
                throw new BusinessException(ResponseCode.RESULT_DATA_NONE);
            }
        } catch (Exception e) {
            logger.error("【捕获异常-删除操作】\r\n异常记录：", e);
            throw new BusinessException(ResponseCode.DATA_DELETE_FAILURE);
        }
    }

}